﻿using SuperSocket.Channel;
using SuperSocket.ProtoBase;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SuperSocket.Client.HttpCode;

internal static class Extensions
{
    /// <summary>
    /// 创建床且启动管道
    /// </summary>
    /// <param name="connector"></param>
    /// <returns></returns>
    public static IChannel<HttpRequest> CreateHttpChannel(this ConnectState connector)
    {
        var channel = connector.CreateChannel(new HttpPipelineFilter(), new ChannelOptions());
        channel.Start();
        return channel;
    }

    /// <summary>
    /// 创建包
    /// </summary>
    /// <typeparam name="TPackageInfo"></typeparam>
    /// <param name="channel"></param>
    /// <returns></returns>
    public static IAsyncEnumerator<TPackageInfo> GetPackageEnumerator<TPackageInfo>(
        this IChannel<TPackageInfo> channel)
    {
        return channel.RunAsync()
            .GetAsyncEnumerator();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="writer"></param>
    /// <returns></returns>
    public static int WriterLine(this IBufferWriter<byte> writer)
    {
        const string newLine = "\r\n";

        return writer.Write(newLine, Encoding.UTF8);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="seq"></param>
    /// <returns></returns>
    public static ReadOnlySequence<byte> CopySequence(ref this ReadOnlySequence<byte> seq)
    {
        SequenceSegment head = null;
        SequenceSegment tail = null;

        foreach (var segment in seq)
        {
            var newSegment = SequenceSegment.CopyFrom(segment);

            if (head == null)
                tail = head = newSegment;
            else
                tail = tail.SetNext(newSegment);
        }

        return new ReadOnlySequence<byte>(head, 0, tail, tail.Memory.Length);
    }

    /// <summary>
    /// 超时
    /// </summary>
    /// <typeparam name="TResult"></typeparam>
    /// <param name="task"></param>
    /// <param name="timeout"></param>
    /// <returns></returns>
    /// <exception cref="TimeoutException"></exception>
    public static async Task<TResult> TimeoutAfter<TResult>(this Task<TResult> task, TimeSpan timeout)
    {
        using var timeoutCancellationTokenSource = new CancellationTokenSource();
        var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token));
        if (completedTask == task)
        {
            timeoutCancellationTokenSource.Cancel();
            return await task; // Very important in order to propagate exceptions
        }
        else
        {
            throw new TimeoutException("The operation has timed out.");
        }
    }

    /// <summary>
    /// 超时
    /// </summary>
    /// <param name="task"></param>
    /// <param name="timeout"></param>
    /// <returns></returns>
    public static async Task TimeoutAfter(this Task task, TimeSpan timeout)
    {
        using var timeoutCancellationTokenSource = new CancellationTokenSource();
        var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token));
        if (completedTask == task)
        {
            timeoutCancellationTokenSource.Cancel();
            await task; // Very important in order to propagate exceptions
        }
        else
        {
            throw new TimeoutException("The operation has timed out.");
        }
    }
}